package com.zmn.oms.business.impl.conf.distribute;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.base.common.data.common.dro.area.AreaDRO;
import com.zmn.base.common.data.dubbo.interfaces.area.AreaListRemoteService;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.Option;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.mcc.common.constant.DpermitConsts;
import com.zmn.oms.business.interfaces.conf.distribute.DistributeWeightPlatBService;
import com.zmn.oms.common.constant.ConfDistributeConsts;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.utils.SpiltListUtil;
import com.zmn.oms.model.dio.conf.distribute.DistributeWeightPlatDIO;
import com.zmn.oms.model.entity.conf.distribute.*;
import com.zmn.oms.model.vo.conf.distribute.DistributeGroupNameValueVO;
import com.zmn.oms.model.vo.conf.distribute.DistributeWeightAreaVO;
import com.zmn.oms.services.interfaces.conf.distribute.DistributeWeightPlatService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类描述：派单配置业务服务
 *
 * @author  liuying
 * @date   2022/02/16 10:48
 */
@Slf4j
@Service
public class DistributeWeightPlatBServiceImpl implements DistributeWeightPlatBService {

    @Resource
    private DistributeWeightPlatService distributeWeightPlatService;
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false, timeout = 200000)
    private AreaListRemoteService areaListRemoteService;

    @Override
    public DistributeWeightPlat findByKey(Integer distributePlatId) {
        if (NumberUtil.isNullOrZero(distributePlatId)) {
            log.error("#DistributeWeightPlatBService#findByPlatAndBizType# find service provider order config failed! " +
                    "reason: {}, distributePlatId: {}", "distributePlatId is null!", distributePlatId);
            return null;
        } else {
            return distributeWeightPlatService.findByKey(distributePlatId);
        }
    }

    @Override
    public DistributeWeightPlat findServiceProviderConfigByPlatAndBizType(Integer plat, Integer bizType) {

        List<DistributeWeightPlat> distributeWeightPlatList = distributeWeightPlatService.findByPlatAndBizType(plat, bizType, ConfDistributeConsts.DISTRIBUTE_SERVICE_PROVIDER);
        if (distributeWeightPlatList.size() > GlobalConsts.NONE) {
            return distributeWeightPlatList.get(GlobalConsts.NONE);
        } else {
            log.error("#DistributeWeightPlatBService#findByPlatAndBizType# find service provider order config failed! " +
                    "reason: {}, plat: {}, bizType: {}", "there is no result from db!", plat, bizType);
            return null;
        }
    }

    @Override
    public List<DistributeWeightPlat> listServiceProviderConfigByPlatIdAndBizType(List<Integer> platList, Integer bizType) {

        List<DistributeWeightPlat> distributeWeightPlatList = distributeWeightPlatService.listByPlatIdAndBizType(platList, bizType, ConfDistributeConsts.DISTRIBUTE_SERVICE_PROVIDER);
        return distributeWeightPlatList;
    }

    @Override
    public DistributeWeightPlat findPlatDirectlyConfigByPlatAndBizTypeAndCityId(Integer plat, Integer bizType, Integer cityId) {

        List<DistributeWeightPlat> distributeWeightPlatList = distributeWeightPlatService.findByPlatAndBizTypeAndCity(
                plat, bizType, cityId, ConfDistributeConsts.DISTRIBUTE_PLAT_DIRECTLY);
        if (distributeWeightPlatList.size() > GlobalConsts.NONE) {
            return distributeWeightPlatList.get(GlobalConsts.NONE);
        } else {
            log.warn("#DistributeWeightPlatBService#findByPlatAndBizType# find plat directly config failed! " +
                    "reason: {}, plat: {}, bizType: {}", "there is no result from db!", plat, bizType);
            return null;
        }
    }

    @Override
    public List<DistributeWeightPlat> listPlatDirectlyConfigByPlatIdAndBizType(List<Integer> platList, Integer bizType) {
        List<DistributeWeightPlat> distributeWeightPlatList = distributeWeightPlatService.listByPlatIdAndBizType(platList, bizType, ConfDistributeConsts.DISTRIBUTE_PLAT_DIRECTLY);
        return distributeWeightPlatList;
    }

    @Override
    public Integer updateByKey(DistributeWeightPlat distributeWeightPlat) {
        return distributeWeightPlatService.updateByKey(distributeWeightPlat);
    }

    @Override
    public Integer updateStatusByQuery(DistributeWeightStatusQuery query) {
        return distributeWeightPlatService.updateStatusByQuery(query);
    }

    @Override
    public Integer updateBatchByKey(List<DistributeWeightPlatDIO> dioList) {
        Assert.state(CollectionUtil.isNotNullOrEmpty(dioList), "传递的集合不能为空");
        Integer updateCount = 0;
        // 分批处理 减轻一次性更新太多 数据库压力大
        if (dioList.size() <= 100) {
            List<Integer> idList = new ArrayList<>(dioList.size());
            dioList.stream().forEach((distributeWeightPlatDIO ->
                    idList.add(distributeWeightPlatDIO.getDistributePlatId())));
            UpdateRepairOrderQuery updateRepairOrderQuery = new UpdateRepairOrderQuery();
            updateRepairOrderQuery.setReworkLimit(dioList.get(0).getReworkLimit());
            updateRepairOrderQuery.setReworkReminderLimit(dioList.get(0).getReworkReminderLimit());
            updateRepairOrderQuery.setUpdater(dioList.get(0).getUpdater());
            updateRepairOrderQuery.setIdList(idList);
            updateCount = distributeWeightPlatService.updateBatchByKey(updateRepairOrderQuery);
        } else {
            List<List<DistributeWeightPlatDIO>> split = SpiltListUtil.split(dioList, 100);
            List<Integer> idList = new ArrayList<>(100);
            for (int i = 0; i < split.size(); i++) {
                try {
                    List<DistributeWeightPlatDIO> distributeWeightPlatDIOS = split.get(i);
                    distributeWeightPlatDIOS.stream().forEach(distributeWeightPlatDIO ->
                            idList.add(distributeWeightPlatDIO.getDistributePlatId()));
                    UpdateRepairOrderQuery updateRepairOrderQuery = new UpdateRepairOrderQuery();
                    updateRepairOrderQuery.setIdList(idList);
                    updateRepairOrderQuery.setReworkLimit(distributeWeightPlatDIOS.get(0).getReworkLimit());
                    updateRepairOrderQuery.setReworkReminderLimit(distributeWeightPlatDIOS.get(0).getReworkReminderLimit());
                    updateRepairOrderQuery.setUpdater(distributeWeightPlatDIOS.get(0).getUpdater());
                    Integer tempCount = distributeWeightPlatService.updateBatchByKey(updateRepairOrderQuery);
                    updateCount += tempCount;
                    log.info("平台直派 批量修改 次数={} 每次数量={} 总共数量={} ", i + 1, tempCount, dioList.size());
                } catch (Exception ex) {
                    log.error("平台直派 返修单批量修改 error", ex);
                } finally {
                    idList.clear();
                }
            }
        }
        log.info("平台直派 批量修改数量 = {} 修改的数量 = {}", dioList.size(), updateCount);
        return updateCount;
    }

    @Override
    public Integer updateStatus(UpdateStatusQuery updateStatusQuery) throws OmsBaseException {
        if (Objects.isNull(updateStatusQuery)) {
            log.error("#DistributeWeightPlatBService#updateStatus# update failed! reason: {}", "query is null");
            throw new OmsBaseException("query is null");
        }
        if (Objects.isNull(updateStatusQuery.getIdList())) {
            log.error("#DistributeWeightPlatBService#updateStatus# update failed! reason: {} query: {}", "idList is null", updateStatusQuery);
            throw new OmsBaseException("idList is null");
        }
        if (NumberUtil.isNullOrZero(updateStatusQuery.getStatus())) {
            log.error("#DistributeWeightPlatBService#updateStatus# update failed! reason: {} query: {}", "status is null", updateStatusQuery);
            throw new OmsBaseException("status is null");
        }
        if (StringUtil.isBlank(updateStatusQuery.getUpdater())) {
            updateStatusQuery.setUpdater("system");
        }
        if (Objects.isNull(updateStatusQuery.getUpdateTime())) {
            updateStatusQuery.setUpdateTime(DateUtil.getNow());
        }
        return distributeWeightPlatService.updateStatus(updateStatusQuery);
    }

    @Override
    public void saveEngineerLevelGroupToCurrent() {
        // 查询全部配置数据
        List<DistributeWeightPlat> distributeWeightPlatList = distributeWeightPlatService.listNotEmptyEngineerLevelGroupListJson();
        for (DistributeWeightPlat distributeWeightPlat : distributeWeightPlatList) {
            this.saveEngineerLevelGroupListJsonToCurrent(distributeWeightPlat);
        }
    }

    /**
     * 保护当前周 工程师分级准入分组
     *
     * @param distributeWeightPlat
     */
    private void saveEngineerLevelGroupListJsonToCurrent(DistributeWeightPlat distributeWeightPlat) {
        List<DistributeWeightEngineerLevelGroup> engineerLevelGroupList = distributeWeightPlat.getEngineerLevelGroupList();

        int size = engineerLevelGroupList.size();

        // 计算每个优先级总的多接单量
        for (int i = size - 2; i >= 0; i--) {
            DistributeWeightEngineerLevelGroup before = engineerLevelGroupList.get(i+1);
            DistributeWeightEngineerLevelGroup item = engineerLevelGroupList.get(i);
            item.setAllProtectionCount(item.getProtectionCount() + Optional.ofNullable(before.getAllProtectionCount()).orElse(0));
        }

        // 处理每个优先级 自然周（周一至周天 7天）多接保护单量
        for (int i = 0; i < size; i++) {
            DistributeWeightEngineerLevelGroup distributeWeightEngineerLevelGroup = engineerLevelGroupList.get(i);
            int allProtectionCount = Optional.ofNullable(distributeWeightEngineerLevelGroup.getAllProtectionCount()).orElse(0);
            int remainder = allProtectionCount % 7;
            int everyDayCount = allProtectionCount / 7;

            // 每周多接保护单量
            Map<Integer, Integer> weekProtectionCountMap = Maps.newHashMap();
            for (int week = 1; week <= 7; week++) {
                weekProtectionCountMap.put(week, everyDayCount);
            }

            // 多余的保护单量，按照 周1、3、5、7、2、4、6 进行分配
            if (remainder > 0) {
                List<Integer> weekList = Lists.newArrayList(1, 3, 5, 7, 2, 4, 6);
                for (int j = 0; j < remainder; j++) {
                    int week = weekList.get(j);
                    weekProtectionCountMap.put(week, weekProtectionCountMap.get(week) + 1);
                }
            }

            // 逻辑调整 每一天保护单量调整为自然周开始到今日的保护单量
            int natureWeekProtectionCount = 0;
            for (int week = 1; week <= 7; week++) {
                natureWeekProtectionCount += weekProtectionCountMap.get(week);
                weekProtectionCountMap.put(week, natureWeekProtectionCount);
            }

            // 分配到每天的多接保护单量
            distributeWeightEngineerLevelGroup.setCurrentWeekProtectionCountMap(weekProtectionCountMap);
        }

        // 保存数据
        distributeWeightPlat.setEngineerLevelGroupListCurrentJson(JSON.toJSONString(engineerLevelGroupList));
        log.info("初始化派单保护单量配置 id:{} data:{}", distributeWeightPlat.getDistributePlatId(), distributeWeightPlat.getEngineerLevelGroupListCurrentJson());
        distributeWeightPlatService.updateEngineerLevelGroupListCurrentJsonByKey(distributeWeightPlat);
    }

    @Override
    public Integer insert(DistributeWeightPlat distributeWeightPlat) {
        return distributeWeightPlatService.insert(distributeWeightPlat);
    }

    @Override
    public List<DistributeWeightAreaVO> listProvince(Integer selectedValue) {
        ResponseDTO<List<AreaDRO>> responseDTO = areaListRemoteService.listAboveByLevelAndStatus(DpermitConsts.AREA_LEVEL_PROVINCE, GlobalConsts.YES);
        return this.parseAreaToVO(responseDTO.getData(), selectedValue);
    }

    @Override
    public List<DistributeWeightAreaVO> listCityByProvince(SearchCityQuery searchCityQuery) {
        if (Objects.isNull(searchCityQuery) || NumberUtil.isNullOrZero(searchCityQuery.getProvinceId())) {
            // 如果没有传省ID 返回空列表
            return new ArrayList<>();
        }

        // 过滤掉已选择的城市
        CheckCityAvailableQuery query =
                CheckCityAvailableQuery.builder()
                        .distributePlatId(searchCityQuery.getDistributePlatId())
                        .bizType(searchCityQuery.getBizType())
                        .plat(searchCityQuery.getPlat())
                        .provinceId(searchCityQuery.getProvinceId())
                        .build();
        List<Integer> beenSetCityIdList = distributeWeightPlatService.hasBeenSetCity(query);

        ResponseDTO<List<AreaDRO>> listResponseDTO = areaListRemoteService.listAreaByParentId(searchCityQuery.getProvinceId());
        List<AreaDRO> baseAreaList = Optional.ofNullable(listResponseDTO.getData()).orElse(Lists.newArrayList());
        List<AreaDRO> result = baseAreaList.stream()
                .filter(item -> !beenSetCityIdList.contains(item.getAreaId()))
                .collect(Collectors.toList());
        return this.parseAreaToVO(result, searchCityQuery.getSelectedValue());
    }

    @Override
    public DistributeWeightPlat findPlatDirectlyConfigByQuery(RobOrderQuery query) {

        List<DistributeWeightPlat> distributeWeightPlatList = distributeWeightPlatService.findPlatDirectlyConfigByQuery(query);
        if (distributeWeightPlatList.size() > GlobalConsts.NONE) {
            return distributeWeightPlatList.get(GlobalConsts.NONE);
        } else {
            log.error("#DistributeWeightPlatBService#findPlatDirectlyConfigByQuery# find plat directly config failed! " +
                    "reason: {}, plat: {}, bizType: {}", "there is no result from db!", query);
            return null;
        }
    }


    @Override
    public List<DistributeGroupNameValueVO> distinctDistributeGroup(Map oldMap, List<Option<Integer>> newList) {
        List<DistributeGroupNameValueVO> result = Lists.newArrayListWithCapacity(newList.size());

        newList.stream().forEach((vtDTO) -> {
            DistributeGroupNameValueVO vo = new DistributeGroupNameValueVO();
            String id = String.valueOf(vtDTO.getValue());
            if (oldMap != null && oldMap.get(id) != null) {
                vo.setId(id);
                vo.setName(vtDTO.getLabel());
                vo.setValue(String.valueOf(oldMap.get(id)));
            } else {
                vo.setId(id);
                vo.setName(vtDTO.getLabel());
                vo.setValue("");
            }
            result.add(vo);
        });
        return result;
    }

    /**
     * 将区域对象转换称下拉框识别的VO对象
     *
     * @param baseAreaList
     * @return
     */
    private List<DistributeWeightAreaVO> parseAreaToVO(List<AreaDRO> baseAreaList, Integer selectedValue) {
        List<DistributeWeightAreaVO> distributeWeightAreaVOList = new ArrayList<>();
        for (AreaDRO baseArea : baseAreaList) {
            DistributeWeightAreaVO distributeWeightAreaVO = DistributeWeightAreaVO.builder()
                    .value(baseArea.getAreaId())
                    .name(baseArea.getName())
                    .selected(Objects.equals(baseArea.getAreaId(), selectedValue))
                    .disabled(false)
                    .build();
            distributeWeightAreaVOList.add(distributeWeightAreaVO);
        }
        return distributeWeightAreaVOList;
    }

}
